package com.lw.common.utils

import android.annotation.SuppressLint
import android.content.Context
import android.os.Environment
import android.os.Process
import android.util.Log
import java.io.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.system.exitProcess

/**
 * Author：yuan
 * Date：2022/002/14
 * desc：全局异常捕获
 */
class MyCrashHandler  //保证只有一个MyCrashHandler实例
private constructor() : Thread.UncaughtExceptionHandler {
    // 系统默认的UncaughtException处理类
    private var mDefaultHandler: Thread.UncaughtExceptionHandler? = null

    //程序的Context对象
    private var mContext: Context? = null

    /**
     * 初始化
     *
     * @param ctx
     */
    fun init(ctx: Context?) {
        mContext = ctx
        //获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler()
        //设置该MyCrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this)
    }

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    override fun uncaughtException(t: Thread, e: Throwable) {
        if (!handleExample(e) && mDefaultHandler != null) {
            // 如果用户没有处理则让系统默认的异常处理器来处理 目的是判断异常是否已经被处理
            mDefaultHandler!!.uncaughtException(t, e)
        } else {
            try { //Sleep 来让线程停止一会是为了显示Toast信息给用户，然后Kill程序
                Thread.sleep(3000)
            } catch (e1: InterruptedException) {
                e1.printStackTrace()
                Log.d("MyCrashHandler", "uncaughtException: " + e1.message)
            } catch (e2: Exception) {
                e2.printStackTrace()
                Log.d("MyCrashHandler", "uncaughtException: " + e2.message)
            }
            // 如果不关闭程序,会导致程序无法启动,需要完全结束进程才能重新启动
            Process.killProcess(Process.myPid())
            exitProcess(1)
            //            restartApp();
        }
    }

    /**
     * 自定义错误处理,收集错误信息 将异常信息保存 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private fun handleExample(ex: Throwable?): Boolean {
        // 如果已经处理过这个Exception,则让系统处理器进行后续关闭处理
        if (ex == null) return false

//        new Thread(() -> {
//            // Toast 显示需要出现在一个线程的消息队列中
//            Looper.prepare();
//            Toast.makeText(mContext, "很抱歉，程序出现异常，即将退出", Toast.LENGTH_SHORT).show();
//            Looper.loop();
//        }).start();

        //将异常记录到本地的文件中
//        saveCrashInfoToFile(ex);
        Log.e("MyCrashHandler", ex.toString())
        return false
    }

    /**
     * 重启应用
     */
    fun restartApp() {
//        Intent intent = new Intent(AppApplication.getContext(), SplashActivity.class);
//        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//        mContext.startActivity(intent);
//        android.os.Process.killProcess(android.os.Process.myPid());
//        System.exit(1);

        // 重启应用
        mContext!!.startActivity(mContext!!.packageManager.getLaunchIntentForPackage(mContext!!.packageName))
        //干掉当前的程序
        Process.killProcess(Process.myPid())
    }

    /**
     * 保存错误信息到文件中
     *
     * @param ex
     */
    private fun saveCrashInfoToFile(ex: Throwable) {
        //获取错误原因
        val writer: Writer = StringWriter()
        val printWriter = PrintWriter(writer)
        ex.printStackTrace(printWriter)
        var exCause = ex.cause
        while (exCause != null) {
            exCause.printStackTrace(printWriter)
            exCause = exCause.cause
        }
        printWriter.close()

        // 错误日志文件名称
        val fileName = "crash-" + timeStampDate() + ".log"

        // 判断sd卡可正常使用
        if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
            //文件存储位置
            val path = Environment.getExternalStorageDirectory().path + "/crash_logInfo/"
            val fl = File(path)
            //创建文件夹
            if (!fl.exists()) {
                fl.mkdirs()
            }
            try {
                val fileOutputStream = FileOutputStream(path + fileName)
                fileOutputStream.write(writer.toString().toByteArray())
                fileOutputStream.close()
            } catch (e1: IOException) {
                e1.printStackTrace()
            } catch (e2: Exception) {
                e2.printStackTrace()
                Log.d("MyCrashHandler", "saveCrashInfoToFile: " + e2.message)
            }
        }
    }

    /**
     * 时间戳转换成日期格式字符串
     * 格式 - 2021-08-05 13:59:05
     */
    @SuppressLint("SimpleDateFormat")
    fun timeStampDate(): String {
        val nowTime = Date(System.currentTimeMillis())
        val sdFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:dd")
        return sdFormatter.format(nowTime)
    }

    companion object {
        // MyCrashHandler实例
        @SuppressLint("StaticFieldLeak")
        @Volatile
        private var myCrashHandler: MyCrashHandler? = null

        // 获取CrashHandler实例 单例模式 - 双重校验锁
        val instance: MyCrashHandler?
            get() {
                if (myCrashHandler == null) {
                    synchronized(MyCrashHandler::class.java) {
                        if (myCrashHandler == null) {
                            myCrashHandler = MyCrashHandler()
                        }
                    }
                }
                return myCrashHandler
            }
    }
}